package com.kexilo.logging.autoconfigure;

import com.kexilo.logging.aspect.LoggingAspect;
import com.kexilo.logging.aspect.LogAspect;
import com.kexilo.logging.properties.LoggingProperties;
import com.kexilo.logging.service.LoggingService;
import com.kexilo.logging.service.LoggingServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.sql.DataSource;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 日志插件自动配置类
 * 根据条件自动装配日志相关组件
 * 
 * @author Kexilo
 */
@AutoConfiguration
@ConditionalOnClass({LoggingService.class})
@ConditionalOnProperty(value = "kexilo.plugin.logging.enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(LoggingProperties.class)
@EnableAsync
public class LoggingAutoConfiguration {
    
    private static final Logger log = LoggerFactory.getLogger(LoggingAutoConfiguration.class);
    
    /**
     * 配置JdbcTemplate Bean
     * 复用admin模块的DataSource配置
     */
    @Bean
    @ConditionalOnClass({DataSource.class, JdbcTemplate.class})
    @ConditionalOnMissingBean(JdbcTemplate.class)
    @ConditionalOnProperty(value = "kexilo.plugin.logging.database.enabled", havingValue = "true", matchIfMissing = true)
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        log.info("配置日志插件JdbcTemplate，复用admin模块DataSource");
        return new JdbcTemplate(dataSource);
    }
    
    /**
     * 配置LoggingService Bean
     */
    @Bean
    @ConditionalOnMissingBean(LoggingService.class)
    public LoggingService loggingService(LoggingProperties properties, 
                                       @Autowired(required = false) JdbcTemplate jdbcTemplate) {
        log.info("配置日志服务，模式: {}, 数据库: {}", 
                properties.getMode(), properties.getDatabase().isEnabled());
        return new LoggingServiceImpl(properties, jdbcTemplate);
    }
    
    /**
     * 配置LoggingAspect Bean
     */
    @Bean
    @ConditionalOnMissingBean(LoggingAspect.class)
    @ConditionalOnProperty(value = "kexilo.plugin.logging.aspect-enabled", havingValue = "true", matchIfMissing = true)
    @ConditionalOnClass({org.aspectj.lang.annotation.Aspect.class})
    public LoggingAspect loggingAspect(LoggingService loggingService, LoggingProperties properties) {
        log.info("配置日志切面，启用状态: {}", properties.isAspectEnabled());
        return new LoggingAspect(loggingService, properties);
    }
    
    /**
     * 配置LogAspect Bean - 从core-common移植的操作日志切面
     */
    @Bean
    @ConditionalOnMissingBean(LogAspect.class)
    @ConditionalOnProperty(value = "kexilo.plugin.logging.enabled", havingValue = "true", matchIfMissing = true)
    @ConditionalOnClass({org.aspectj.lang.annotation.Aspect.class})
    public LogAspect logAspect(LoggingService loggingService) {
        log.info("配置操作日志切面（原core-common的LogAspect）");
        return new LogAspect();
    }
    
    /**
     * 配置异步任务执行器
     */
    @Bean("loggingTaskExecutor")
    @ConditionalOnProperty(value = "kexilo.plugin.logging.async.enabled", havingValue = "true", matchIfMissing = true)
    @ConditionalOnMissingBean(name = "loggingTaskExecutor")
    public ThreadPoolTaskExecutor loggingTaskExecutor(LoggingProperties properties) {
        LoggingProperties.AsyncProperties async = properties.getAsync();
        
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(async.getCorePoolSize());
        executor.setMaxPoolSize(async.getMaxPoolSize());
        executor.setQueueCapacity(async.getQueueCapacity());
        executor.setThreadNamePrefix(async.getThreadNamePrefix());
        executor.setKeepAliveSeconds((int) async.getKeepAliveTime().getSeconds());
        executor.setAllowCoreThreadTimeOut(async.isAllowCoreThreadTimeOut());
        
        // 拒绝策略：调用者运行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        
        // 等待任务完成后关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        
        executor.initialize();
        
        log.info("配置日志异步执行器，核心线程数: {}, 最大线程数: {}, 队列容量: {}", 
                async.getCorePoolSize(), async.getMaxPoolSize(), async.getQueueCapacity());
        
        return executor;
    }
    
    /**
     * 日志插件健康检查配置
     */
    @Bean
    @ConditionalOnClass(name = "org.springframework.boot.actuate.health.HealthIndicator")
    @ConditionalOnProperty(value = "kexilo.plugin.logging.health.enabled", havingValue = "true")
    public LoggingHealthIndicator loggingHealthIndicator(LoggingService loggingService, 
                                                       LoggingProperties properties) {
        log.info("配置日志插件健康检查");
        return new LoggingHealthIndicator(loggingService, properties);
    }
    
    /**
     * 日志插件健康检查指示器
     */
    public static class LoggingHealthIndicator {
        
        private final LoggingService loggingService;
        private final LoggingProperties properties;
        
        public LoggingHealthIndicator(LoggingService loggingService, LoggingProperties properties) {
            this.loggingService = loggingService;
            this.properties = properties;
        }
        
        public String checkHealth() {
            try {
                if (!properties.isEnabled()) {
                    return "DISABLED";
                }
                
                boolean available = loggingService.isAvailable();
                return available ? "UP" : "DOWN";
                
            } catch (Exception e) {
                return "DOWN: " + e.getMessage();
            }
        }
        
        public String getServiceInfo() {
            return String.format("LoggingService[%s] - Mode: %s, Database: %s, Async: %s", 
                    loggingService.getServiceName(),
                    properties.getMode(),
                    properties.getDatabase().isEnabled(),
                    properties.getAsync().isEnabled());
        }
    }
}
